/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : app_freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "stdio.h"
#include "tim.h"
#include "usart.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
typedef StaticTask_t osStaticThreadDef_t;
typedef StaticTimer_t osStaticTimerDef_t;
typedef StaticSemaphore_t osStaticSemaphoreDef_t;
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//���Բ���ϳ�Ϊһ�����������͵�ʱ��������Ҳ��
#define PASSWORD_INPUT        (psd3 + psd2*10 + psd1*100)
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
HexToBin led_ctrl;
uint8_t key_times,key_temp;
uint8_t pwm2_freq=1,pwm2_duty=50;       //��ʼ�Ƿ���(2K 50%)     ���ģʽ(1Khz 10%)
uint16_t cap15_cnt1,cap15_cnt2,cap15_freq,cap15_duty;
uint8_t uart_buf[2];
uint8_t rx_buf[10],rx_cnt;

_Bool sys_state;
_Bool led2_alarm;
uint8_t psd1=10,psd2=10,psd3=10;     //��λʮλ��λ
uint16_t PSD=123;   //Ĭ������ֵ
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
/* Definitions for LEDTask */
osThreadId_t LEDTaskHandle;
uint32_t LEDTaskBuffer[ 128 ];
osStaticThreadDef_t LEDTaskControlBlock;
const osThreadAttr_t LEDTask_attributes = {
  .name = "LEDTask",
  .stack_mem = &LEDTaskBuffer[0],
  .stack_size = sizeof(LEDTaskBuffer),
  .cb_mem = &LEDTaskControlBlock,
  .cb_size = sizeof(LEDTaskControlBlock),
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for KEYTask */
osThreadId_t KEYTaskHandle;
uint32_t KEYTaskBuffer[ 128 ];
osStaticThreadDef_t KEYTaskControlBlock;
const osThreadAttr_t KEYTask_attributes = {
  .name = "KEYTask",
  .stack_mem = &KEYTaskBuffer[0],
  .stack_size = sizeof(KEYTaskBuffer),
  .cb_mem = &KEYTaskControlBlock,
  .cb_size = sizeof(KEYTaskControlBlock),
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for PWMTask */
osThreadId_t PWMTaskHandle;
uint32_t PWMTaskBuffer[ 128 ];
osStaticThreadDef_t PWMTaskControlBlock;
const osThreadAttr_t PWMTask_attributes = {
  .name = "PWMTask",
  .stack_mem = &PWMTaskBuffer[0],
  .stack_size = sizeof(PWMTaskBuffer),
  .cb_mem = &PWMTaskControlBlock,
  .cb_size = sizeof(PWMTaskControlBlock),
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for LCDTask */
osThreadId_t LCDTaskHandle;
uint32_t LCDTaskBuffer[ 256 ];
osStaticThreadDef_t LCDTaskControlBlock;
const osThreadAttr_t LCDTask_attributes = {
  .name = "LCDTask",
  .stack_mem = &LCDTaskBuffer[0],
  .stack_size = sizeof(LCDTaskBuffer),
  .cb_mem = &LCDTaskControlBlock,
  .cb_size = sizeof(LCDTaskControlBlock),
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for UARTTask */
osThreadId_t UARTTaskHandle;
uint32_t UARTTaskBuffer[ 256 ];
osStaticThreadDef_t UARTTaskControlBlock;
const osThreadAttr_t UARTTask_attributes = {
  .name = "UARTTask",
  .stack_mem = &UARTTaskBuffer[0],
  .stack_size = sizeof(UARTTaskBuffer),
  .cb_mem = &UARTTaskControlBlock,
  .cb_size = sizeof(UARTTaskControlBlock),
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for CPUTask */
osThreadId_t CPUTaskHandle;
uint32_t CPUTaskBuffer[ 512 ];
osStaticThreadDef_t CPUTaskControlBlock;
const osThreadAttr_t CPUTask_attributes = {
  .name = "CPUTask",
  .stack_mem = &CPUTaskBuffer[0],
  .stack_size = sizeof(CPUTaskBuffer),
  .cb_mem = &CPUTaskControlBlock,
  .cb_size = sizeof(CPUTaskControlBlock),
  .priority = (osPriority_t) osPriorityLow,
};
/* Definitions for myTimer01 */
osTimerId_t myTimer01Handle;
osStaticTimerDef_t myTimer01ControlBlock;
const osTimerAttr_t myTimer01_attributes = {
  .name = "myTimer01",
  .cb_mem = &myTimer01ControlBlock,
  .cb_size = sizeof(myTimer01ControlBlock),
};
/* Definitions for myTimer02 */
osTimerId_t myTimer02Handle;
osStaticTimerDef_t myTimer02ControlBlock;
const osTimerAttr_t myTimer02_attributes = {
  .name = "myTimer02",
  .cb_mem = &myTimer02ControlBlock,
  .cb_size = sizeof(myTimer02ControlBlock),
};
/* Definitions for myBinarySemRX */
osSemaphoreId_t myBinarySemRXHandle;
osStaticSemaphoreDef_t myBinarySemRXControlBlock;
const osSemaphoreAttr_t myBinarySemRX_attributes = {
  .name = "myBinarySemRX",
  .cb_mem = &myBinarySemRXControlBlock,
  .cb_size = sizeof(myBinarySemRXControlBlock),
};
/* Definitions for myBinarySemCPU */
osSemaphoreId_t myBinarySemCPUHandle;
osStaticSemaphoreDef_t myBinarySemCPUControlBlock;
const osSemaphoreAttr_t myBinarySemCPU_attributes = {
  .name = "myBinarySemCPU",
  .cb_mem = &myBinarySemCPUControlBlock,
  .cb_size = sizeof(myBinarySemCPUControlBlock),
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void LED_Task(void *argument);
void KEY_Task(void *argument);
void PWM_Task(void *argument);
void LCD_Task(void *argument);
void UART_Task(void *argument);
void CPU_Task(void *argument);
void Callback01(void *argument);
void Callback02(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* Hook prototypes */
void configureTimerForRunTimeStats(void);
unsigned long getRunTimeCounterValue(void);

/* USER CODE BEGIN 1 */
/* Functions needed when configGENERATE_RUN_TIME_STATS is on */
__IO uint32_t RUN_Time=0;
void configureTimerForRunTimeStats(void)
{
    RUN_Time=0;
    MX_TIM17_Init();
    HAL_TIM_Base_Start_IT(&htim17);
}

unsigned long getRunTimeCounterValue(void)
{
    return RUN_Time;
}
/* USER CODE END 1 */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */
    LED_Control(led_ctrl.hex);
    LCD_Init();
    LCD_Clear(Black);
    LCD_SetTextColor(White);
    LCD_SetBackColor(Black);
    HAL_UART_Receive_IT(&huart1,uart_buf,1);
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
    HAL_TIM_IC_Start_IT(&htim15,TIM_CHANNEL_1);
  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* Create the semaphores(s) */
  /* creation of myBinarySemRX */
  myBinarySemRXHandle = osSemaphoreNew(1, 0, &myBinarySemRX_attributes);

  /* creation of myBinarySemCPU */
  myBinarySemCPUHandle = osSemaphoreNew(1, 0, &myBinarySemCPU_attributes);

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* Create the timer(s) */
  /* creation of myTimer01 */
  myTimer01Handle = osTimerNew(Callback01, osTimerOnce, NULL, &myTimer01_attributes);

  /* creation of myTimer02 */
  myTimer02Handle = osTimerNew(Callback02, osTimerOnce, NULL, &myTimer02_attributes);

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of LEDTask */
  LEDTaskHandle = osThreadNew(LED_Task, NULL, &LEDTask_attributes);

  /* creation of KEYTask */
  KEYTaskHandle = osThreadNew(KEY_Task, NULL, &KEYTask_attributes);

  /* creation of PWMTask */
  PWMTaskHandle = osThreadNew(PWM_Task, NULL, &PWMTask_attributes);

  /* creation of LCDTask */
  LCDTaskHandle = osThreadNew(LCD_Task, NULL, &LCDTask_attributes);

  /* creation of UARTTask */
  UARTTaskHandle = osThreadNew(UART_Task, NULL, &UARTTask_attributes);

  /* creation of CPUTask */
  CPUTaskHandle = osThreadNew(CPU_Task, NULL, &CPUTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_LED_Task */
/**
  * @brief  Function implementing the LEDTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_LED_Task */
void LED_Task(void *argument)
{
  /* USER CODE BEGIN LED_Task */
  /* Infinite loop */
  for(;;)
  {
      LED_Control(led_ctrl.hex);
      if(led2_alarm)led_ctrl.b.b2 = !led_ctrl.b.b2;
      else led_ctrl.b.b2=0;
      osDelay(100);
  }
  /* USER CODE END LED_Task */
}

/* USER CODE BEGIN Header_KEY_Task */
/**
* @brief Function implementing the KEYTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_KEY_Task */
void KEY_Task(void *argument)
{
  /* USER CODE BEGIN KEY_Task */
  /* Infinite loop */
  for(;;)
  {
      KEY_Read();
      if(Trg)key_temp=Trg;
      if(Cont)key_times++;
      if(Trg==0 && Cont==0 && key_temp){
          if(key_times>=25){
              if(key_temp==0x01)osSemaphoreRelease(myBinarySemCPUHandle);
          }else {
              if(!sys_state){
                  if(key_temp==0x01){
                      if(psd1==10)psd1=0;
                      else psd1=(psd1+1)%10;
                  }
                  if(key_temp==0x02){
                      if(psd2==10)psd2=0;
                      else psd2=(psd2+1)%10;
                  }
                  if(key_temp==0x04){
                      if(psd3==10)psd3=0;
                      else psd3=(psd3+1)%10;
                  }
                  if(key_temp==0x08){
                      static uint8_t cnt=0;       //�����������
                      if(PSD==PASSWORD_INPUT){
                          sys_state=led_ctrl.b.b1=1;   //����������ȷ����ת��״̬�������
                          osTimerStart(myTimer01Handle,5000);//HAL_TIM_Base_Start_IT(&htim17); //������ʱ��
                          pwm2_freq=2;pwm2_duty=10;cnt=0;
                      }
                      else {
                          psd1=psd2=psd3=10;         //��������������ڵ�ǰ���棬����ָ�Ĭ��
                          if(++cnt==3){
                              led2_alarm=1;cnt=0;
                              osTimerStart(myTimer02Handle,5000);//HAL_TIM_Base_Start_IT(&htim17); //������ʱ��
                          }
                      }
                  }
              }
          }key_times=0;key_temp=0;
      }
    osDelay(20);
  }
  /* USER CODE END KEY_Task */
}

/* USER CODE BEGIN Header_PWM_Task */
/**
* @brief Function implementing the PWMTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_PWM_Task */
void PWM_Task(void *argument)
{
  /* USER CODE BEGIN PWM_Task */
    static uint8_t old_freq,old_duty;
  /* Infinite loop */
  for(;;)
  {
      if(old_freq!=pwm2_freq || old_duty!=pwm2_duty){
          HAL_TIM_PWM_Stop(&htim2,TIM_CHANNEL_2);
          __HAL_TIM_SET_AUTORELOAD(&htim2,(1000/pwm2_freq-1));
          __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,((1000/pwm2_freq-1)*pwm2_duty/100));
          HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
          old_freq=pwm2_freq;old_duty=pwm2_duty;
          led_ctrl.b.b7 = !led_ctrl.b.b7;
      }
    osDelay(100);
  }
  /* USER CODE END PWM_Task */
}

/* USER CODE BEGIN Header_LCD_Task */
/**
* @brief Function implementing the LCDTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_LCD_Task */
void LCD_Task(void *argument)
{
  /* USER CODE BEGIN LCD_Task */
    uint8_t buf[21];
  /* Infinite loop */
  for(;;)
  {
      sprintf((char *)buf,"key:%3d,psd:%03d(%1d)",key_times,PSD,led2_alarm);
      LCD_DisplayStringLine(Line0,buf);
      sprintf((char *)buf,"pwm:%1d-%2d cap:%4d",pwm2_freq,pwm2_duty,cap15_freq);       //����TIM15������TIM2���PWM��(PA1-PA2)����
      LCD_DisplayStringLine(Line8,buf);
      sprintf((char *)buf,"uart:%8s ,%2d",rx_buf,cap15_duty);
      LCD_DisplayStringLine(Line9,buf);
      if(sys_state==0){
          sprintf((char *)buf,"       PSD");
          LCD_DisplayStringLine(Line2,buf);
          if(psd1==10)sprintf((char *)buf,"    B1:@    ");
          else sprintf((char *)buf,"    B1:%1d    ",psd1);

          LCD_DisplayStringLine(Line4,buf);
          if(psd2==10)sprintf((char *)buf,"    B2:@   ");
          else sprintf((char *)buf,"    B2:%1d   ",psd2);
          LCD_DisplayStringLine(Line5,buf);
          if(psd3==10)sprintf((char *)buf,"    B3:@   ");
          else sprintf((char *)buf,"    B3:%1d   ",psd3);
          LCD_DisplayStringLine(Line6,buf);
      }else {
          sprintf((char *)buf,"       STA");
          LCD_DisplayStringLine(Line2,buf);
          sprintf((char *)buf,"    F:%4dHz",pwm2_freq*1000);
          LCD_DisplayStringLine(Line4,buf);
          sprintf((char *)buf,"    D:%2d%%",pwm2_duty);
          LCD_DisplayStringLine(Line5,buf);
          LCD_ClearLine(Line6);
      }
    osDelay(80);
  }
  /* USER CODE END LCD_Task */
}

/* USER CODE BEGIN Header_UART_Task */
/**
* @brief Function implementing the UARTTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_UART_Task */
void UART_Task(void *argument)
{
  /* USER CODE BEGIN UART_Task */
  /* Infinite loop */
  for(;;)
  {
      osSemaphoreAcquire(myBinarySemRXHandle,HAL_MAX_DELAY);
      rx_cnt=0;
      if(rx_buf[3]=='-'){
          //������(����)��֤��ȷ
          if(PSD != (rx_buf[0]-48)*100 + (rx_buf[1]-48)*10 + (rx_buf[2]-48))return;//printf("[debug]password old error\r\n");
          //������(��ʽ)��֤��ȷ
          for (int i = 4; i < 6; ++i) {
              if(rx_buf[i]<'0' || '9'<rx_buf[i])return;//printf("[debug]password new error-%d:%c\r\n",i,rx_buf[i]);
          }
          PSD=(rx_buf[4]-48)*100 + (rx_buf[5]-48)*10 + (rx_buf[6]-48);
      }
    osDelay(100);
  }
  /* USER CODE END UART_Task */
}

/* USER CODE BEGIN Header_CPU_Task */
/**
* @brief Function implementing the CPUTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_CPU_Task */
void CPU_Task(void *argument)
{
  /* USER CODE BEGIN CPU_Task */
  uint8_t cpu_info[300];
  /* Infinite loop */
  for(;;)
  {
      osSemaphoreAcquire(myBinarySemCPUHandle,HAL_MAX_DELAY);
      vTaskList((char *)cpu_info);
      printf("%s",cpu_info);
      printf("------------\r\n");
      vTaskGetRunTimeStats((char *)cpu_info);
      printf("%s",cpu_info);
    osDelay(1000);
  }
  /* USER CODE END CPU_Task */
}

/* Callback01 function */
void Callback01(void *argument)
{
  /* USER CODE BEGIN Callback01 */
    led_ctrl.b.b1=sys_state=0;
    psd1=psd2=psd3=10;
    pwm2_freq=1;pwm2_duty=50;
  /* USER CODE END Callback01 */
}

/* Callback02 function */
void Callback02(void *argument)
{
  /* USER CODE BEGIN Callback02 */
    led2_alarm=0;
  /* USER CODE END Callback02 */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart==&huart1){
        HAL_UART_Receive_IT(&huart1,uart_buf,1);
        rx_buf[rx_cnt++]=uart_buf[0];//printf("%c",uart_buf[0]);
        if(rx_cnt==7)osSemaphoreRelease(myBinarySemRXHandle);       //û���жϰ汾�ģ�
    }
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)        //����Ƶ�ʺ�ռ�ձ�
{
    static uint8_t tim15_state=0;
    if(htim==&htim15){
        if(tim15_state==0){                     //��һ�������ز�������ʼ��ʱ
            __HAL_TIM_SET_COUNTER(&htim15,0);   //����CNT=0
            __HAL_TIM_SET_CAPTUREPOLARITY(&htim15,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);  //���ó��½����ж�
            tim15_state=1;
        }else if(tim15_state==1){               //��ȡ t1(us),����Ϊ�������ж�
            cap15_cnt1= __HAL_TIM_GET_COUNTER(&htim15);  //��ȡ t1
            __HAL_TIM_SET_CAPTUREPOLARITY(&htim15,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);   //���ó��������ж�
            tim15_state=2;
        }else if(tim15_state==2){               //��ȡ t2(us),����Ƶ��
            cap15_cnt2=  __HAL_TIM_GET_COUNTER(&htim15);
            cap15_freq = 1000000/cap15_cnt2;
            cap15_duty = cap15_cnt1*100/cap15_cnt2;
            tim15_state=0;
        }
        HAL_TIM_IC_Start_IT(&htim15,TIM_CHANNEL_1);
    }
}


/* USER CODE END Application */

